bitkeeper revision 1.1159.44.1 (4124c99bzYQ86nF2sa6s-nSiOfibyQ)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 19 Aug 2004 15:39:07 +0000 (15:39 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Thu, 19 Aug 2004 15:39:07 +0000 (15:39 +0000)
Clean up mapping of I/O memory and Xen-heap memory. We define two
'dummy domains' for this purpose which can be specified to
MMUEXT_SET_FOREIGNDOM.

17 files changed:
linux-2.4.26-xen-sparse/arch/xen/mm/ioremap.c
linux-2.4.26-xen-sparse/drivers/char/mem.c
linux-2.6.7-xen-sparse/arch/xen/i386/mm/ioremap.c
linux-2.6.7-xen-sparse/drivers/char/mem.c
linux-2.6.7-xen-sparse/drivers/xen/privcmd/privcmd.c
tools/libxc/xc.h
tools/libxc/xc_linux_save.c
xen/arch/x86/memory.c
xen/arch/x86/setup.c
xen/common/dom0_ops.c
xen/common/domain.c
xen/common/kernel.c
xen/common/memory.c
xen/common/page_alloc.c
xen/include/asm-x86/mm.h
xen/include/hypervisor-ifs/hypervisor-if.h
xen/include/xen/sched.h

index 9cd34cd9252f4531e61e992b0ebb0f9dbb188ffe..34c95c84b55290edb2095f770ee1a472d22889d8 100644 (file)
@@ -115,17 +115,10 @@ int direct_remap_area_pages(struct mm_struct *mm,
 #define MAX_DIRECTMAP_MMU_QUEUE 130
     mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
 
-    if ( domid != 0 )
-    {
-        u[0].ptr  = MMU_EXTENDED_COMMAND;
-        u[0].val  = MMUEXT_SET_FOREIGNDOM;
-        u[0].val |= (unsigned long)domid << 16;
-        v = w = &u[1];
-    }
-    else
-    {
-        v = w = &u[0];
-    }
+    u[0].ptr  = MMU_EXTENDED_COMMAND;
+    u[0].val  = MMUEXT_SET_FOREIGNDOM;
+    u[0].val |= (unsigned long)domid << 16;
+    v = w = &u[1];
 
     start_address = address;
 
index 5635b269aaf80585b647e66c6e06384f455af655..f0d8502190ada6b89f503a064efffb3fbb3b8e8d 100644 (file)
@@ -237,6 +237,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
        if (!(start_info.flags & SIF_PRIVILEGED))
                return -ENXIO;
 
+       if (file->private_data == NULL)
+               file->private_data = (void *)(unsigned long)DOMID_IO;
+
        /* DONTCOPY is essential for Xen as copy_page_range is broken. */
        vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
index e6d1e95cb4fdbdfb58333562e63671aca69e3703..3fb6ea9aa0136ed668da313f02904e46580bf7af 100644 (file)
@@ -415,17 +415,10 @@ int direct_remap_area_pages(struct mm_struct *mm,
 #define MAX_DIRECTMAP_MMU_QUEUE 130
     mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
 
-    if ( domid != 0 )
-    {
-        u[0].ptr  = MMU_EXTENDED_COMMAND;
-        u[0].val  = MMUEXT_SET_FOREIGNDOM;
-        u[0].val |= (unsigned long)domid << 16;
-        v = w = &u[1];
-    }
-    else
-    {
-        v = w = &u[0];
-    }
+    u[0].ptr  = MMU_EXTENDED_COMMAND;
+    u[0].val  = MMUEXT_SET_FOREIGNDOM;
+    u[0].val |= (unsigned long)domid << 16;
+    v = w = &u[1];
 
     start_address = address;
 
index ceea2b5ffdef35e0ca7a099dcb64226e1193db09..ed3df13f65d4a879603e59d81dd0fd089082eb63 100644 (file)
@@ -247,6 +247,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
        if (!(start_info.flags & SIF_PRIVILEGED))
                return -ENXIO;
 
+       if (file->private_data == NULL)
+               file->private_data = (void *)(unsigned long)DOMID_IO;
+
        /* DONTCOPY is essential for Xen as copy_page_range is broken. */
        vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
index aa7a1d9a01fe15a3a927601f59eef31478565bd9..c57bdf6b239c535dd5ce63b9c5445c6f7e8318e3 100644 (file)
@@ -138,17 +138,10 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
         if ( (m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end )
         { ret = -EFAULT; goto batch_err; }
 
-        if ( m.dom != 0 )
-        {
-            u[0].ptr  = MMU_EXTENDED_COMMAND;
-            u[0].val  = MMUEXT_SET_FOREIGNDOM;
-            u[0].val |= (unsigned long)m.dom << 16;
-            v = w = &u[1];
-        }
-        else
-        {
-            v = w = &u[0];
-        }
+        u[0].ptr  = MMU_EXTENDED_COMMAND;
+        u[0].val  = MMUEXT_SET_FOREIGNDOM;
+        u[0].val |= (unsigned long)m.dom << 16;
+        v = w = &u[1];
 
         p = m.arr;
         addr = m.addr;
index 974ac975f2d68d0e81ae9e8e15989b9230b0473a..8b54ed020776d19fee521451a755f5364f3cf6c6 100644 (file)
@@ -154,6 +154,8 @@ int xc_rrobin_global_set(int xc_handle, u64 slice);
 int xc_rrobin_global_get(int xc_handle, u64 *slice);
 
 #define DOMID_SELF              (0x7FF0U)
+#define DOMID_IO                (0x7FF1U)
+#define DOMID_XEN               (0x7FF2U)
 
 typedef struct {
 #define EVTCHNSTAT_closed       0  /* Chennel is not in use.                 */
index 5a47b30f5633bca8aac883585385d6d32677359d..def9f7516dfa51e74c81cdd6aee3b2ed1526d95e 100644 (file)
@@ -423,7 +423,7 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt)
     mfn_to_pfn_table_start_mfn = xc_get_m2p_start_mfn( xc_handle );
 
     live_mfn_to_pfn_table = 
-       mfn_mapper_map_single(xc_handle, 0x7FFFU
+       mfn_mapper_map_single(xc_handle, DOMID_XEN
                              PAGE_SIZE*1024, PROT_READ, 
                              mfn_to_pfn_table_start_mfn );
 
index cb0cf2f19ab0d62c964b23c9649bc72927aea52b..5152e396480a8bb77d4841925c43fd55b9404777 100644 (file)
@@ -137,14 +137,49 @@ static struct {
  */
 #define FOREIGNDOM (percpu_info[smp_processor_id()].foreign ? : current)
 
-void ptwr_init_backpointers(void);
+/* Private domain structs for DOMID_XEN and DOMID_IO. */
+static struct domain *dom_xen, *dom_io;
 
 void arch_init_memory(void)
 {
+    static void ptwr_init_backpointers(void);
+    unsigned long mfn;
+
     memset(percpu_info, 0, sizeof(percpu_info));
 
     vm_assist_info[VMASST_TYPE_writeable_pagetables].enable =
         ptwr_init_backpointers;
+
+    /* Initialise to a magic of 0x55555555 so easier to spot bugs later. */
+    memset(machine_to_phys_mapping, 0x55, 4<<20);
+
+    /*
+     * Initialise our DOMID_XEN domain.
+     * Any Xen-heap pages that we will allow to be mapped will have
+     * their domain field set to dom_xen.
+     */
+    dom_xen = alloc_domain_struct();
+    atomic_set(&dom_xen->refcnt, 1);
+    dom_xen->domain = DOMID_XEN;
+
+    /*
+     * Initialise our DOMID_IO domain.
+     * This domain owns no pages but is considered a special case when
+     * mapping I/O pages, as the mappings occur at the priv of the caller.
+     */
+    dom_io = alloc_domain_struct();
+    atomic_set(&dom_io->refcnt, 1);
+    dom_io->domain = DOMID_IO;
+
+    /* M2P table is mappable read-only by privileged domains. */
+    for ( mfn = virt_to_phys(&machine_to_phys_mapping[0<<20])>>PAGE_SHIFT;
+          mfn < virt_to_phys(&machine_to_phys_mapping[1<<20])>>PAGE_SHIFT;
+          mfn++ )
+    {
+        frame_table[mfn].u.inuse.count_info = 1 | PGC_allocated;
+        frame_table[mfn].u.inuse.type_info  = 1 | PGT_gdt_page; /* non-RW */
+        frame_table[mfn].u.inuse.domain     = dom_xen;
+    }
 }
 
 static void __invalidate_shadow_ldt(struct domain *d)
@@ -178,7 +213,7 @@ static inline void invalidate_shadow_ldt(struct domain *d)
 }
 
 
-int alloc_segdesc_page(struct pfn_info *page)
+static int alloc_segdesc_page(struct pfn_info *page)
 {
     unsigned long *descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
     int i;
@@ -345,11 +380,15 @@ get_page_from_l1e(
 
     if ( unlikely(!pfn_is_ram(pfn)) )
     {
-        if ( IS_PRIV(current) )
+        /* Revert to caller privileges if FD == DOMID_IO. */
+        if ( d == dom_io )
+            d = current;
+
+        if ( IS_PRIV(d) )
             return 1;
 
-        if ( IS_CAPABLE_PHYSDEV(current) )
-            return domain_iomem_in_pfn(current, pfn);
+        if ( IS_CAPABLE_PHYSDEV(d) )
+            return domain_iomem_in_pfn(d, pfn);
 
         MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
         return 0;
@@ -827,9 +866,16 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
 
         if ( !IS_PRIV(d) )
         {
-            MEM_LOG("Dom %u has no privilege to set subject domain",
-                    d->domain);
-            okay = 0;
+            switch ( domid )
+            {
+            case DOMID_IO:
+                get_knownalive_domain(e = dom_io);
+                break;
+            default:
+                MEM_LOG("Dom %u cannot set foreign dom\n", d->domain);
+                okay = 0;
+                break;
+            }
         }
         else
         {
@@ -839,8 +885,19 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
             percpu_info[cpu].foreign = e = find_domain_by_id(domid);
             if ( e == NULL )
             {
-                MEM_LOG("Unknown domain '%u'", domid);
-                okay = 0;
+                switch ( domid )
+                {
+                case DOMID_XEN:
+                    get_knownalive_domain(e = dom_xen);
+                    break;
+                case DOMID_IO:
+                    get_knownalive_domain(e = dom_io);
+                    break;
+                default:
+                    MEM_LOG("Unknown domain '%u'", domid);
+                    okay = 0;
+                    break;
+                }
             }
         }
         break;
@@ -926,7 +983,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
          * the lock so they'll spin waiting for us.
          */
         if ( unlikely(e->tot_pages++ == 0) )
-            get_domain(e);
+            get_knownalive_domain(e);
         list_add_tail(&page->list, &e->page_list);
 
     reassign_fail:        
@@ -1493,7 +1550,7 @@ int ptwr_do_page_fault(unsigned long addr)
     return 0;
 }
 
-void ptwr_init_backpointers(void)
+static void ptwr_init_backpointers(void)
 {
     struct pfn_info *page;
     unsigned long pde;
index e629930ab6c8df12cc492ddace61cf6f8c8e6105..3d18ebd4ee00f6100fb3980536f05a7fb8d0e21e 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/domain_page.h>
 #include <asm/pdb.h>
 
+extern void arch_init_memory(void);
 extern void init_IRQ(void);
 extern void trap_init(void);
 extern void time_init(void);
@@ -360,6 +361,8 @@ void __init start_of_day(void)
     time_init(); /* installs software handler for HZ clock. */
     init_apic_mappings(); /* make APICs addressable in our pagetables. */
 
+    arch_init_memory();
+
 #ifndef CONFIG_SMP    
     APIC_init_uniprocessor();
 #else
index 6c8abcb8f8a2b490dbfe0b4f5db810cd6e2c76ea..1f1e911b73461eedb09328e1b57940b62499187c 100644 (file)
 
 extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int);
 extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
-extern void arch_getdomaininfo_ctxt(struct domain *, full_execution_context_t *);
+extern void arch_getdomaininfo_ctxt(
+    struct domain *, full_execution_context_t *);
 
 static inline int is_free_domid(domid_t dom)
 {
     struct domain *d;
 
-    if ( dom >= DOMID_SELF )
+    if ( dom >= DOMID_FIRST_RESERVED )
         return 0;
 
     if ( (d = find_domain_by_id(dom)) == NULL )
@@ -66,7 +67,7 @@ static int allocate_domid(domid_t *pdom)
     }
 
     /* Couldn't find a free domain id in 0..topdom, try higher. */
-    for ( dom = topdom; dom < DOMID_SELF; dom++ )
+    for ( dom = topdom; dom < DOMID_FIRST_RESERVED; dom++ )
     {
         if ( is_free_domid(dom) )
         {
@@ -167,7 +168,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
         domid_t           dom;
 
         dom = op->u.createdomain.domain;
-        if ( (dom > 0) && (dom < DOMID_SELF) )
+        if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
         {
             ret = -EINVAL;
             if ( !is_free_domid(dom) )
index cac4c2edf07d15d34bf830a9d63b75525a1d613b..4ca9f581356d103eb05125fdf854e4f5d393c8d8 100644 (file)
@@ -39,11 +39,18 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
     d->domain    = dom_id;
     d->processor = cpu;
     d->create_time = NOW();
-    /* Initialise the sleep_lock */
     spin_lock_init(&d->sleep_lock);
  
     memcpy(&d->thread, &idle0_task.thread, sizeof(d->thread));
 
+    spin_lock_init(&d->page_alloc_lock);
+    INIT_LIST_HEAD(&d->page_list);
+    d->max_pages = d->tot_pages = 0;
+
+    /* Per-domain PCI-device list. */
+    spin_lock_init(&d->pcidev_lock);
+    INIT_LIST_HEAD(&d->pcidev_list);
+
     if ( d->domain != IDLE_DOMAIN_ID )
     {
         if ( init_event_channels(d) != 0 )
@@ -59,16 +66,8 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
 
         d->addr_limit = USER_DS;
         
-        spin_lock_init(&d->page_alloc_lock);
-        INIT_LIST_HEAD(&d->page_list);
-        d->max_pages = d->tot_pages = 0;
-
        arch_do_createdomain(d);
 
-        /* Per-domain PCI-device list. */
-        spin_lock_init(&d->pcidev_lock);
-        INIT_LIST_HEAD(&d->pcidev_list);
-
         sched_add_domain(d);
 
         write_lock_irqsave(&tasklist_lock, flags);
index d4cd43ae9d71f6a297a2f75baa8f89300d26b27f..707cede7f193bfe8c39109b7395f94d7b18aff96 100644 (file)
@@ -304,9 +304,6 @@ void cmain(multiboot_info_t *mbi)
 
     start_of_day();
 
-    /* Add CPU0 idle task to the task hash list */
-    task_hash[TASK_HASH(IDLE_DOMAIN_ID)] = &idle0_task;
-
     /* Create initial domain 0. */
     new_dom = do_createdomain(0, 0);
     if ( new_dom == NULL )
index 8e513b55e33441d4e0be20c9c30c9cc06ac21b04..2dfdd10e07d2913576aa5f0768c6b650095c9cab 100644 (file)
@@ -37,14 +37,8 @@ struct pfn_info *frame_table;
 unsigned long frame_table_size;
 unsigned long max_page;
 
-extern void arch_init_memory(void);
-
 void __init init_frametable(void *frametable_vstart, unsigned long nr_pages)
 {
-    unsigned long mfn;
-
-    arch_init_memory();
-
     max_page = nr_pages;
     frame_table_size = nr_pages * sizeof(struct pfn_info);
     frame_table_size = (frame_table_size + PAGE_SIZE - 1) & PAGE_MASK;
@@ -54,17 +48,4 @@ void __init init_frametable(void *frametable_vstart, unsigned long nr_pages)
         panic("Not enough memory for frame table - reduce Xen heap size?\n");
 
     memset(frame_table, 0, frame_table_size);
-
-    /* Initialise to a magic of 0x55555555 so easier to spot bugs later. */
-    memset(machine_to_phys_mapping, 0x55, 4<<20);
-
-    /* Pin the ownership of the MP table so that DOM0 can map it later. */
-    for ( mfn = virt_to_phys(&machine_to_phys_mapping[0<<20])>>PAGE_SHIFT;
-          mfn < virt_to_phys(&machine_to_phys_mapping[1<<20])>>PAGE_SHIFT;
-          mfn++ )
-    {
-        frame_table[mfn].u.inuse.count_info = 1 | PGC_allocated;
-        frame_table[mfn].u.inuse.type_info = 1 | PGT_gdt_page; /* non-RW */
-        frame_table[mfn].u.inuse.domain = &idle0_task;
-    }
 }
index b3b056fd6898ea700737197cc01d101c6d7913a0..323ecd244e1e810ad576f1e2984d1859fc248de4 100644 (file)
@@ -393,7 +393,7 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, int order)
     }
 
     if ( unlikely(d->tot_pages == 0) )
-        get_domain(d);
+        get_knownalive_domain(d);
 
     d->tot_pages += 1 << order;
 
index c0143352e0186191ed7170cd432ea22f0bf229ad..a2fc40e0b32bc0c7ad6ce584c7106bc1ac0a48a6 100644 (file)
@@ -108,7 +108,7 @@ struct pfn_info
         /* _dom holds an allocation reference */                            \
         (_pfn)->u.inuse.count_info = PGC_allocated | 1;                     \
         if ( unlikely((_dom)->xenheap_pages++ == 0) )                       \
-            get_domain(_dom);                                               \
+            get_knownalive_domain(_dom);                                    \
         spin_unlock(&(_dom)->page_alloc_lock);                              \
     } while ( 0 )
 
index 1c28062c5b21d4d928e934b8d017db7f6b09ae9d..efcaeb8abb283eb6b182a065e9b7f9f238c83dc8 100644 (file)
  * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
  * Updates an entry in a page table. If updating an L1 table, and the new
  * table entry is valid/present, the mapped frame must belong to the FD, if
- * an FD has been specified. If attempting to map an I/O page, then the FD
- * is ignored, but the calling domain must have sufficient privilege.
+ * an FD has been specified. If attempting to map an I/O page then the
+ * caller assumes the privilege of the FD.
+ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
+ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
  * ptr[:2]  -- Machine address of the page-table entry to modify.
  * val      -- Value to write.
  * 
  *   val[7:0] == MMUEXT_SET_FOREIGNDOM:
  *   val[31:15] -- Domain to set as the Foreign Domain (FD).
  *                 (NB. DOMID_SELF is not recognised)
+ *                 If FD != DOMID_IO then the caller must be privileged.
  * 
  *   val[7:0] == MMUEXT_REASSIGN_PAGE:
  *   ptr[:2]  -- A machine address within the page to be reassigned to the FD.
 #ifndef __ASSEMBLY__
 
 typedef u16 domid_t;
+
+/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
+#define DOMID_FIRST_RESERVED (0x7FF0U)
+
 /* DOMID_SELF is used in certain contexts to refer to oneself. */
-#define DOMID_SELF  (0x7FF0U)
-/* NB. IDs >= 0x7FF1 are reserved for future use. */
+#define DOMID_SELF (0x7FF0U)
+
+/*
+ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
+ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
+ * is useful to ensure that no mappings to the OS's own heap are accidentally
+ * installed. (e.g., in Linux this could cause havoc as reference counts
+ * aren't adjusted on the I/O-mapping code path).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
+ * be specified by any calling domain.
+ */
+#define DOMID_IO   (0x7FF1U)
+
+/*
+ * DOMID_XEN is used to allow privileged domains to map restricted parts of
+ * Xen's heap space (e.g., the machine_to_phys table).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
+ * the caller is privileged.
+ */
+#define DOMID_XEN  (0x7FF2U)
 
 /*
  * Send an array of these to HYPERVISOR_mmu_update().
index 06b6faf6cc41fc5b3e560f05f3f50641b5afb550..af74cf5380100dd69370a698ffc788c8d877d3e4 100644 (file)
@@ -164,11 +164,26 @@ struct domain *alloc_domain_struct();
 #define DOMAIN_DESTRUCTED (1<<31) /* assumes atomic_t is >= 32 bits */
 #define put_domain(_d) \
   if ( atomic_dec_and_test(&(_d)->refcnt) ) domain_destruct(_d)
+
+/*
+ * Use this when you don't have an existing reference to @d. It returns
+ * FALSE if @d is being destructed.
+ */
 static inline int get_domain(struct domain *d)
 {
     atomic_inc(&d->refcnt);
     return !(atomic_read(&d->refcnt) & DOMAIN_DESTRUCTED);
 }
+
+/*
+ * Use this when you already have, or are borrowing, a reference to @d.
+ * In this case we know that @d cannot be destructed under our feet.
+ */
+static inline void get_knownalive_domain(struct domain *d)
+{
+    atomic_inc(&d->refcnt);
+    ASSERT(!(atomic_read(&d->refcnt) & DOMAIN_DESTRUCTED));
+}
   
 extern struct domain *do_createdomain(
     domid_t dom_id, unsigned int cpu);